﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;

using System.Reflection;


namespace gxc2csharp
{
   class GXCFunctionCallParser
   {
      
      
      private string GXCClass { get; set; }
      private string FunctionName { get; set; }
      private List<string> Argumnets { get; set; }
      private Dictionary<string,string> Symbols;
      private int startOfFunctionDef, openingBraket, closingBraket;
      public GXCFunctionCallParser( Dictionary<string, string> Symbols)
      {
         Argumnets = new List<string>();
         this.Symbols = Symbols;
         
        
      }

      private void ParseArgumets(string function, int openingBraket, int closingBraket)
      {
         string args = function.Substring(openingBraket + 1, closingBraket - openingBraket - 1);
         int index = args.IndexOf("\"");
         string stringArgument="";
         if(index !=-1)
         {
            int end = args.IndexOf("\"",index+1);
            if (end !=-1 && args.IndexOf(',', index,end-index+1) != -1)
            {
               stringArgument = args.Substring(index, end - index);
               args = args.Remove(index, end - index+1);
               args = args.Insert(index, "@VIVEK@");
            }
         }
         string[] arguments = args.Split(',');
         
         
         foreach (var argument in arguments)
         {
            if (string.IsNullOrEmpty(argument) == false)
            {
               if (argument == "@VIVEK@")
                  Argumnets.Add(stringArgument.Trim());
               else
                  Argumnets.Add(argument.Trim());
            }
         }
         
      }
      public string GetCSharpSignatureForFunction(string lineWithfunctionCall)
      {
         string csharpCall="";
         string outputLine = "";
         ParseGXCFunctionCall(lineWithfunctionCall);
         if (string.IsNullOrEmpty(FunctionName))
            return lineWithfunctionCall;
         MethodInfo info = AnalyzeCSharpFunction(GXCClass, FunctionName);
         ParameterInfo[] paramInfo=null;
         if (info != null)
         {
            if (info.IsStatic)
            {
               csharpCall = GXCClass;
            }
            paramInfo = info.GetParameters();
            if (Argumnets.Count-1 == paramInfo.Length )
            {
               if (Symbols.ContainsKey(Argumnets[0]))
               {
                  csharpCall = Argumnets[0];
                  Argumnets.RemoveAt(0);
               }
               else
               {
                  System.Diagnostics.Trace.TraceError("Unknown symbol found");
               }

            }
        

            csharpCall += "." + FunctionName;
            csharpCall += "(";

            if (Argumnets.Count >= 1)
            {
              
               int i = 0;
               foreach (var argument in Argumnets)
               {
                  var parmeter = paramInfo[i];
                  if (parmeter.ParameterType.IsByRef)
                     csharpCall += "ref ";
                  if(IsConstantArgument(argument))
                     csharpCall+="Constant."+argument+',';
                  else
                     csharpCall += argument + ",";
                  i++;
                  
                 
               }
               csharpCall = csharpCall.Remove(csharpCall.Length - 1);
            }
            csharpCall += ")";
            outputLine = lineWithfunctionCall.Remove(startOfFunctionDef, closingBraket - startOfFunctionDef + 1);
            outputLine = outputLine.Insert(startOfFunctionDef, " " + csharpCall);

         }
         else
         {
            outputLine = "//TODO: --Enable Call --  " + lineWithfunctionCall+Environment.NewLine;
            outputLine += lineWithfunctionCall+Environment.NewLine; 


         }
        
         return outputLine;


      }

      private bool IsConstantArgument(string argument)
      {
        const string ALL_CAPS_PATTERN = "[a-z]";
        Regex All_Caps_Regex =   new Regex (ALL_CAPS_PATTERN);
        if (All_Caps_Regex.IsMatch(argument))
        {
           return false;
        }
        return true;


      }

      private MethodInfo AnalyzeCSharpFunction(string GXCClass, string FunctionName)
      {

         char[] prefixes = { 'i', 'I', 'r' };
         MethodInfo info = null;
         string function = FunctionName.Trim();
         if(FunctionName.StartsWith("Create"))
            function="Create";
         else if (FunctionName.StartsWith("Destroy"))
            function = "Dispose";


         string fullClassNamespace = "Geosoft.GXNet." + GXCClass + ",geonet";
         Type t = Type.GetType(fullClassNamespace);
         if (t != null)
         {
            
            info = t.GetMethod(function);
            if (info == null)
            {
               foreach (var prefix in prefixes)
               {
                  info = t.GetMethod(prefix + function);
                  if (info != null)
                  {
                     FunctionName = info.Name;
                     break;
                  }
               }
            }
            if(info == null)
               info = t.GetMethod(FunctionName.Trim());

         }
         
         return info;

      }

      private void ParseGXCFunctionCall(string function)
      {
         Argumnets.Clear();
         GXCClass = "";
         FunctionName = "";
         int assign = function.IndexOf("=");
         int index =0;
         if(assign != -1)
            index = function.IndexOf('_',assign);
         else
             index = function.IndexOf('_');
         if (index != -1)
         {
            openingBraket = function.IndexOf('(', index);
            if (openingBraket != -1)
            {
               GXCClass =("C"+ function.Substring(index + 1, openingBraket - index - 1)).Trim();
               startOfFunctionDef = GetStartOfFunctionIndex(function, openingBraket);
               if(startOfFunctionDef >index)
                  startOfFunctionDef = GetStartOfFunctionIndex(function, openingBraket);

               if (startOfFunctionDef != -1)
               {
                  FunctionName = function.Substring(startOfFunctionDef, index - startOfFunctionDef).Trim();
               }
               else
               {
                  startOfFunctionDef = function.LastIndexOf('(', index); //maybe if statement
                  if (startOfFunctionDef != -1)
                     FunctionName = function.Substring(startOfFunctionDef, index - startOfFunctionDef);

               }

               closingBraket = function.IndexOf(")", index);
               ParseArgumets(function, openingBraket, closingBraket);

            }
         }
      }

      private int GetStartOfFunctionIndex(string function, int openingBraket)
      {
         int index = openingBraket-1;
         while (char.IsWhiteSpace(function[index]))
            index--;
         for(int i=index; i>0;i--)
         {
            char ch  = function[i];
            if (char.IsLetterOrDigit(ch) == false && ch != '_')
               return i+1;
         }
         return -1;
            
      }
      
   }
}
